package algutil.cryptage;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

public class DESEncrypter {

	private Cipher ecipher;
	private Cipher dcipher;
	// Buffer used to transport the bytes from one stream to another
	private byte[] buf = new byte[1024];

	public DESEncrypter(SecretKey key) {
		// Create an 8-byte initialization vector
		byte[] iv = new byte[] { (byte) 0x8E, 0x12, 0x39, (byte) 0x9C, 0x07,
				0x72, 0x6F, 0x5A };
		AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
		try {
			ecipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
			dcipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

			// CBC requires an initialization vector
			ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
			dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
		} catch (java.security.InvalidAlgorithmParameterException e) {
		} catch (javax.crypto.NoSuchPaddingException e) {
		} catch (java.security.NoSuchAlgorithmException e) {
		} catch (java.security.InvalidKeyException e) {
		}
	}

	public DESEncrypter(String passPhrase) throws InvalidKeySpecException,
			NoSuchAlgorithmException, NoSuchPaddingException,
			InvalidKeyException, InvalidAlgorithmParameterException {
		// Create an 8-byte initialization vector
		byte[] iv = new byte[] { (byte) 0x8E, 0x12, 0x39, (byte) 0x9C, 0x07,
				0x72, 0x6F, 0x5A };
		int iterationCount = 19;

		// Create the key
		KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), iv,
				iterationCount);
		SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES")
				.generateSecret(keySpec);
		ecipher = Cipher.getInstance(key.getAlgorithm());
		dcipher = Cipher.getInstance(key.getAlgorithm());

		// Prepare the parameter to the ciphers
		AlgorithmParameterSpec paramSpec = new PBEParameterSpec(iv,
				iterationCount);

		// Create the ciphers
		ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
		dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
	}

	public void encrypt(InputStream in, OutputStream out) throws IOException {
		// Bytes written to out will be encrypted
		out = new CipherOutputStream(out, ecipher);

		// Read in the cleartext bytes and write to out to encrypt
		int numRead = 0;
		while ((numRead = in.read(buf)) >= 0) {
			out.write(buf, 0, numRead);
		}
		out.close();
	}

	public void decrypt(InputStream in, OutputStream out) throws IOException {
		// Bytes read from in will be decrypted
		in = new CipherInputStream(in, dcipher);

		// Read in the decrypted bytes and write the cleartext to out
		int numRead = 0;
		while ((numRead = in.read(buf)) >= 0) {
			out.write(buf, 0, numRead);
		}
		out.close();
	}

	public String encrypt(String str) throws IllegalBlockSizeException,
			BadPaddingException, UnsupportedEncodingException {
		// Encode the string into bytes using utf-8
		byte[] utf8 = str.getBytes("UTF8");

		// Encrypt
		byte[] enc = ecipher.doFinal(utf8);

		// Encode bytes to base64 to get a string
		return new sun.misc.BASE64Encoder().encode(enc);
	}

	public String decrypt(String str) throws IOException,
			IllegalBlockSizeException, BadPaddingException {
		// Decode base64 to get bytes
		byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);

		// Decrypt
		byte[] utf8 = dcipher.doFinal(dec);

		// Decode using utf-8
		return new String(utf8, "UTF8");
	}

	public static void main(String[] args) throws NoSuchAlgorithmException,
			InvalidKeySpecException, InvalidKeyException,
			NoSuchPaddingException, InvalidAlgorithmParameterException,
			IOException, IllegalBlockSizeException, BadPaddingException {

		// Generate a temporary key. In practice, you would save this key.
		// See also Encrypting with DES Using a Pass Phrase.
		SecretKey key = KeyGenerator.getInstance("DES").generateKey();

		System.out.println("algo=" + key.getAlgorithm());
		System.out.println("format=" + key.getFormat());
		System.out.println("key=" + key);

		// Create encrypter/decrypter class
		// DESEncrypter encrypter = new DESEncrypter(key);
		DESEncrypter encrypter = new DESEncrypter("mon codde!");

		// Encrypt File
		//encrypter.encrypt(new FileInputStream(new File("d:/mp3.mp3")),new FileOutputStream(new File("d:/mp3.crypte")));

		// Decrypt File
		//encrypter.decrypt(new FileInputStream(new File("d:/mp3.crypte")),new FileOutputStream(new File("d:/mp3.decrypte")));

		String stringToEncrypt = "SHAKA PONK (France)\\SHAKA PONK - 2011 The Geeks and the Jerkin' Socks\\SHAKA PONK - 01 Let's Bang.mp3";
		String encrypted = encrypter.encrypt(stringToEncrypt);
		String decrypted = encrypter.decrypt(encrypted);
		System.out.println("stringToEncrypt=" + stringToEncrypt);
		System.out.println("encrypted      =" + encrypted);
		System.out.println("decrypted      =" + decrypted);
	}
}
